/*
 * Galaxium Messenger
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 *
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;
using System.Text;

using Gdk;
using Gtk;

using Anculus.Core;

using Galaxium.Core;
using Galaxium.Gui;
using Galaxium.Gui.GtkGui;
using Galaxium.Protocol;
using Galaxium.Protocol.Gui;

namespace Galaxium.Gui.GtkGui
{
	public class CellRendererContact: Gtk.CellRendererText
	{
		int _emoticonmargin = 1;
		string _text;
		string _markup = string.Empty;
		List<ITextChunk> _chunks = new List<ITextChunk> ();
		IProtocol _protocol;
		bool _showEmoticons = true;
		
		public bool ShowEmoticons
		{
			get { return _showEmoticons; }
			set { _showEmoticons = value; }
		}

		public new string Markup
		{
			get { return _markup; }
			set
			{
				if (_markup == value)
					return;
				
				//Log.Debug ("Old markup: {0}", _markup.Replace ("\n", ""));

				_markup = value;

				char accel_char;
				Pango.AttrList attrs;
				Pango.Global.ParseMarkup (_markup, char.MaxValue, out attrs, out _text, out accel_char);
				
				//Log.Debug ("New markup: {0}", _markup.Replace ("\n", ""));
				
				SplitMarkup ();
			}
		}
		
		public int EmoticonMargin
		{
			get { return _emoticonmargin; }
			set { _emoticonmargin = value; }
		}
		
		public CellRendererContact (IProtocol protocol)
		{
			_protocol = protocol;
		}
		
		void SplitMarkup ()
		{
			lock (_chunks)
			{
				_chunks.Clear ();
				
				if (!string.IsNullOrEmpty (_text))
					_chunks.AddRange (PangoUtility.SplitMarkup (_markup, _protocol, null));
			}
		}
		
		protected override void Render (Drawable window,
		                                Gtk.Widget widget,
		                                Gdk.Rectangle background_area,
		                                Gdk.Rectangle cell_area,
		                                Gdk.Rectangle expose_area,
		                                Gtk.CellRendererState flags)
    	{
			int xoffset, yoffset, width, height;
			GetSize (widget, ref cell_area, out xoffset, out yoffset, out width, out height);

			int y = (int) Ypad;
			int x = (int) Xpad;
			
			int pw, ph, lineheight = 0;
			
			Gtk.StateType state;
			if (!this.Sensitive)
				state = Gtk.StateType.Insensitive;
			else if ((flags & Gtk.CellRendererState.Selected) == Gtk.CellRendererState.Selected)
				state = (widget.HasFocus ? Gtk.StateType.Selected : Gtk.StateType.Active);
			else if (((flags & Gtk.CellRendererState.Prelit) == Gtk.CellRendererState.Prelit) && (widget.State == Gtk.StateType.Prelight))
				state = Gtk.StateType.Prelight;
			else
				state = (widget.State == Gtk.StateType.Insensitive ? Gtk.StateType.Insensitive : Gtk.StateType.Normal);

			lock (_chunks)
			{
				int fontMaxHeight = 0;
				int fontHeight = 16;
				
				foreach (ITextChunk chunk in _chunks)
				{
					if ((!_showEmoticons) || (chunk.Type != TextChunkType.Emoticon))
					{
						char accel_char;
						Pango.AttrList attrs;
						string txt;
						Pango.Global.ParseMarkup (chunk.Text, char.MaxValue, out attrs, out txt, out accel_char);
						
						if (txt == "\n")
						{
							y += lineheight;
							x = (int)Xpad;
							lineheight = 0;
							fontMaxHeight = 0;
							attrs.Dispose ();
							continue;
						}
						
						if (string.IsNullOrEmpty (txt))
						{
							Log.Warn ("No text in markup {0}", chunk.Text);
							
							foreach (ITextChunk c in _chunks)
								Log.Debug ("{0}: {1}", c.Type, c.Text);
							
							attrs.Dispose ();
							continue;
						}
						
						Pango.Layout lay = widget.CreatePangoLayout (txt);
						lay.FontDescription = this.FontDesc;
						lay.Wrap = this.WrapMode;
						lay.Ellipsize = this.Ellipsize;
						lay.Attributes = attrs;
						
						lay.GetPixelSize(out pw, out ph);
						
						Pango.Rectangle inkRect, logicalRect;
						lay.GetPixelExtents (out inkRect, out logicalRect);
						fontHeight = logicalRect.Height;
						
						if (fontHeight > fontMaxHeight)
							fontMaxHeight = fontHeight;
						
						if (ph > lineheight)
							lineheight = ph;
						
						//check if we need ellipsizing
						if (Ellipsize != Pango.EllipsizeMode.None && (cell_area.X + x + pw) > (cell_area.Width + cell_area.X))
							lay.Width = Convert.ToInt32 ((cell_area.Width - xoffset - x - 2 * Xpad) * Pango.Scale.PangoScale);
						
						//paint the layout
						Gtk.Style.PaintLayout (widget.Style,
						                       window,
						                       state,
						                       true,
						                       cell_area,
						                       widget,
						                       "cellrenderertext",
						                       cell_area.X + x,
						                       cell_area.Y + y + ((fontMaxHeight - fontHeight) / 2),
						                       lay);
						
						lay.Dispose ();
						attrs.Dispose ();
						
						x += pw;
					}
					else
					{
						x += _emoticonmargin;
						
						IEmoticon emot = ((EmoticonTextChunk)chunk).Emoticon;
						Gdk.Pixbuf pixbuf = new Pixbuf (emot.Data);
						
						int newH = fontHeight;
						int newW = (int)(((double)pixbuf.Width / (double)pixbuf.Height) * newH);
						Gdk.Pixbuf scaled = pixbuf.ScaleSimple (newW, newH, InterpType.Bilinear);
						
						if (scaled != null)
						{
							if (cell_area.X + x < (cell_area.Width + cell_area.X))
								window.DrawPixbuf (null, scaled, 0, 0, cell_area.X + x,
								                   cell_area.Y + y, scaled.Width, scaled.Height,
								                   RgbDither.None, 0, 0);
							
							x += scaled.Width + _emoticonmargin;
							
							scaled.Dispose ();
						}
						else
							Log.Error ("Unable to scale emoticon pixmap");
						
						pixbuf.Dispose ();
					}
				}
			}
		}
	}
}
